//!  实现一个栈回溯的功能

use core::arch::asm;

#[derive(Clone, Debug, Copy, Eq, PartialEq, Ord, PartialOrd)]
#[repr(C)]
struct StackFrame {
    s_fp: usize,
    s_ra: usize,
}

unsafe extern "C" {
    fn stext();
    fn etext();
}

// check the addr whether is valid.
fn kernel_text(addr: usize) -> bool {
    if addr >= stext as usize && addr < etext as usize {
        true
    } else {
        false
    }
}

// 遍历栈帧
#[inline(never)]
#[unsafe(no_mangle)]
fn walk_stack_frame() {
    // 所有的变量必须在前面初始化好，这样sp的位置就固定了
    let mut sp: usize = 0;
    let mut fp: usize = 0;
    let mut pc: usize = 0;
    let mut low = 0usize;
    let mut stack_frame_pointer = core::ptr::null::<StackFrame>();

    // 获取相关寄存器的值
    unsafe {
        asm!(
        "mv {0}, sp",
        "mv {1}, s0",
        out(reg) sp,
        out(reg) fp
        );
    }

    // 初始化
    pc = walk_stack_frame as usize;
    // 打印本级的栈帧
    println!("本级的[0x{:016x} - 0x{:016x}] pc 0x{:016x}", sp, fp, pc);

    loop {
        if !kernel_text(pc) {
            break;
        }
        low = sp + size_of::<StackFrame>();
        if fp < low || fp & 0xf != 0 {
            break;
        }

        stack_frame_pointer = (fp - 16) as _;
        sp = fp;
        fp = unsafe { (*stack_frame_pointer).s_fp };
        pc = unsafe { (*stack_frame_pointer).s_ra - 4 };

        if kernel_text(pc) {
            println!("[0x{:016x} - 0x{:016x}] pc 0x{:016x}", sp, fp, pc);
        }
    }
}

#[inline(never)]
#[unsafe(no_mangle)]
pub fn dum_stack() {
    println!("Call Frame:\n");
    walk_stack_frame();
}
